声明
本篇文章转载自JAVA反射与注解,作者先讲解了Java反射,然后在Java反射的基础上又对Java注解进行了讲解,我主要是对其中Java反射部分进行摘录。
什么是Java反射
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
什么是反射机制
反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法。
反射机制能做什么
反射机制主要提供了以下功能:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理
Java反射机制的应用场景是什么
- 逆向代码 ,例如反编译
- 与注解相结合的框架 例如Retrofit
- 单纯的反射机制应用框架 例如EventBus
- 动态生成类框架 例如Gson
理解Class类和类类型
想要了解反射首先理解一下Class类,它是反射实现的基础。
类是java.lang.Class类的实例对象,而Class是所有类的类(There is a class named Class)
对于普通的对象,我们一般都会这样创建和表示:
1
| Code code1 = new Code();
|
上面说了,所有的类都是Class的对象,那么如何表示呢,可不可以通过如下方式呢:
但是我们查看Class的源码时,是这样写的:
1 2 3
| private Class(ClassLoader loader) { classLoader = loader; }
|
可以看到构造器是私有的,只有JVM可以创建Class的对象,因此不可以像普通类一样new一个Class对象,虽然我们不能new一个Class对象,但是却可以通过已有的类得到一个Class对象,共有三种方式,如下:
1 2 3
| Class c1 = Code.class; Class c2 = code1.getClass(); Class c3 = Class.forName("com.trigl.reflect.Code");
|
这里,c1、c2、c3都是Class的对象,他们是完全一样的,而且有个学名,叫做Code的类类型(class type)。
这里就让人奇怪了,前面不是说Code是Class的对象吗,而c1、c2、c3也是Class的对象,那么Code和c1、c2、c3不就一样了吗?为什么还叫Code什么类类型?这里不要纠结于它们是否相同,只要理解类类型是干什么的就好了,顾名思义,类类型就是类的类型,也就是描述一个类是什么,都有哪些东西,所以我们可以通过类类型知道一个类的属性和方法,并且可以调用一个类的属性和方法,这就是反射的基础。
举个简单例子代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException { Class class1=ReflectDemo.class; System.out.println(class1.getName()); ReflectDemo demo2= new ReflectDemo(); Class c2 = demo2.getClass(); System.out.println(c2.getName()); Class class3 = Class.forName("com.tengj.reflect.ReflectDemo"); System.out.println(class3.getName()); } }
|
执行结果:
1 2 3
| com.tengj.reflect.ReflectDemo com.tengj.reflect.ReflectDemo com.tengj.reflect.ReflectDemo
|
Java反射相关操作
在这里先看一下sun为我们提供了那些反射机制中的类:
- java.lang.Class;
- java.lang.reflect.Constructor;
- java.lang.reflect.Field;
- java.lang.reflect.Method;
- java.lang.reflect.Modifier;
前面我们知道了怎么获取Class,那么我们可以通过这个Class干什么呢?
总结如下:
- 获取成员方法Method
- 获取成员变量Field
- 获取构造函数Constructor
下面来具体介绍:
获取成员方法信息
两个参数分别表示方法名和方法参数类的类类型列表
1 2 3 4 5 6 7 8
| public Method getDeclaredMethod(String name, Class<?>... parameterTypes) public Method getMethod(String name, Class<?>... parameterTypes) Method[] methods = class1.getDeclaredMethods(); Method[] allMethods = class1.getMethods(); Method method = class1.getMethod("info", String.class); Method declaredMethod = class1.getDeclaredMethod("info", String.class);
|
举个例子:
例如类A有如下一个方法:
1 2 3
| public void fun(String name,int age) { System.out.println("我叫"+name+",今年"+age+"岁"); }
|
现在知道A有一个对象a,那么就可以通过:
1 2 3 4
| Class c = Class.forName("com.tengj.reflect.Person"); Object o = c.newInstance(); Method method = c.getMethod("fun", String.class, int.class); method.invoke(o, "tengj", 10);
|
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class Person { private String name; private int age; private String msg="hello wrold"; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person() { } private Person(String name) { this.name = name; System.out.println(name); } public void fun() { System.out.println("fun"); } public void fun(String name,int age) { System.out.println("我叫"+name+",今年"+age+"岁"); } } public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Object o = c.newInstance(); Method method = c.getMethod("fun", String.class, int.class); method.invoke(o, "tengj", 10); } catch (Exception e) { e.printStackTrace(); } } }
|
执行结果:
有时候我们想获取类中所有成员方法的信息,要怎么办。可以通过以下几步来实现:
获取所有方法的数组:
1 2 3 4
| Class c = Class.forName("com.tengj.reflect.Person"); Method[] methods = c.getDeclaredMethods(); 或者: Method[] methods = c.getMethods();
|
然后循环这个数组就得到每个方法了:
1
| for (Method method : methods)
|
完整代码如下:
person类跟上面一样,这里以及后面就不贴出来了,只贴关键代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Method[] methods = c.getDeclaredMethods(); for(Method m:methods){ String methodName= m.getName(); System.out.println(methodName); } } catch (Exception e) { e.printStackTrace(); } } }
|
执行结果如下:
1 2 3 4 5 6
| getName setName setAge fun fun getAge
|
这里如果把c.getDeclaredMethods();改成c.getMethods();执行结果如下,多了很多方法,以为把Object里面的方法也打印出来了,因为Object是所有类的父类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| getName setName getAge setAge fun fun wait wait wait equals toString hashCode getClass notify notifyAll
|
获取成员变量信息
想一想成员变量中都包括什么:成员变量类型+成员变量名
类的成员变量也是一个对象,它是java.lang.reflect.Field
的一个对象,所以我们通过java.lang.reflect.Field
里面封装的方法来获取这些信息。
单独获取某个成员变量,通过Class类的以下方法实现:
1 2 3 4 5 6 7 8
| public Field getDeclaredField(String name) public Field getField(String name) Field[] allFields = class1.getDeclaredFields(); Field[] publicFields = class1.getFields(); Field ageField = class1.getDeclaredField("age"); Field desField = class1.getField("des");
|
举个例子:
例如一个类A有如下成员变量:
如果A有一个对象a,那么就可以这样得到其成员变量:
1 2
| Class c = a.getClass(); Field field = c.getDeclaredField("msg");
|
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Field field = c.getDeclaredField("msg"); Object o = c.newInstance(); field.setAccessible(true); Object msg = field.get(o); System.out.println(msg); } catch (Exception e) { e.printStackTrace(); } } }
|
执行结果:
同样,如果想要获取所有成员变量的信息,可以通过以下几步
获取所有成员变量的数组:
1
| Field[] fields = c.getDeclaredFields();
|
遍历变量数组,获得某个成员变量field
1
| for (Field field : fields)
|
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Field[] fields = c.getDeclaredFields(); for(Field field :fields){ System.out.println(field.getName()); } } catch (Exception e) { e.printStackTrace(); } } }
|
执行结果如下:
获取构造函数
最后再想一想构造函数中都包括什么:构造函数参数
同上,类的成构造函数也是一个对象,它是java.lang.reflect.Constructor
的一个对象,所以我们通过java.lang.reflect.Constructor
里面封装的方法来获取这些信息。
单独获取某个构造函数,通过Class
类的以下方法实现:
1 2 3 4 5 6 7 8
| public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) public Constructor<T> getConstructor(Class<?>... parameterTypes) Constructor<?>[] allConstructors = class1.getDeclaredConstructors(); Constructor<?>[] publicConstructors = class1.getConstructors(); Constructor<?> constructor = class1.getDeclaredConstructor(String.class); Constructor publicConstructor = class1.getConstructor(String.class);
|
举个例子:
例如类A有如下一个构造函数:
1 2 3
| public A(String a, int b) { }
|
那么就可以通过:
1
| Constructor constructor = a.getDeclaredConstructor(String.class, int.class);
|
来获取这个构造函数。
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Constructor constructor = c.getDeclaredConstructor(String.class); constructor.setAccessible(true); constructor.newInstance("tengj"); } catch (Exception e) { e.printStackTrace(); } } }
|
执行结果:
注意:Class的newInstance方法,只能创建只包含无参数的构造函数的类,如果某类只有带参数的构造函数,那么就要使用另外一种方式:
1
| fromClass.getDeclaredConstructor(String.class).newInstance("tengj");
|
获取所有的构造函数,可以通过以下步骤实现:
完整代码:
1 2 3 4 5 6 7 8 9 10 11
| public class ReflectDemo { public static void main(String[] args){ Constructor[] constructors = c.getDeclaredConstructors(); for(Constructor constructor:constructors){ System.out.println(constructor); } } catch (Exception e) { e.printStackTrace(); } } }
|
执行结果:
1 2
| public com.tengj.reflect.Person() public com.tengj.reflect.Person(java.lang.String)
|
其他方法
注解需要用到的:
1 2 3 4
| Annotation[] annotations = (Annotation[]) class1.getAnnotations(); Annotation annotation = (Annotation) class1.getAnnotation(Deprecated.class); Type genericSuperclass = class1.getGenericSuperclass(); Type Type[] interfaceTypes = class1.getGenericInterfaces();
|
获取class对象的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| boolean isPrimitive = class1.isPrimitive(); boolean isArray = class1.isArray(); boolean isAnnotation = class1.isAnnotation(); boolean isInterface = class1.isInterface(); boolean isEnum = class1.isEnum(); boolean isAnonymousClass = class1.isAnonymousClass(); boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class); String className = class1.getName(); Package aPackage = class1.getPackage(); String simpleName = class1.getSimpleName(); int modifiers = class1.getModifiers(); Class<?>[] declaredClasses = class1.getDeclaredClasses(); Class<?> declaringClass = class1.getDeclaringClass(); getSuperclass():获取某类的父类 getInterfaces():获取某类实现的接口
|